package com.learning.rpc.config.util;

import com.learning.rpc.common.tool.SpiUtils;
import com.learning.rpc.config.ProtocolConfig;
import com.learning.rpc.config.ReferenceConfig;
import com.learning.rpc.config.RegistryConfig;
import com.learning.rpc.config.ServiceConfig;
import com.learning.rpc.registry.RegistryService;
import com.learning.rpc.rpc.Invoker;
import com.learning.rpc.rpc.cluster.ClusterInvoker;
import com.learning.rpc.rpc.protocol.Protocol;
import com.learning.rpc.rpc.proxy.ProxyFactory;

import java.net.NetworkInterface;
import java.net.URI;

/**
 * ClassName: RpcBootstrap
 * Description: RpcBootstrap
 * Date: 2022/5/10 22:23 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class RpcBootstrap {
    /**
     * 暴露 service 服务
     *
     * @param serviceConfig serviceConfig
     */
    public static void export(ServiceConfig serviceConfig) {

        // 1. 创建代理对象（静态代理）
        Invoker invoker = ProxyFactory.getInvoker(serviceConfig.getReference(), serviceConfig.getService());

        try {
            // 2. 根据服务定义的协议，依次暴露。 如果有多个协议那就暴露多次
            for (ProtocolConfig protocolConfig : serviceConfig.getProtocolConfigs()) {
                // 2.1 组织 URL
                // 协议名称://IP:port/service全类名?参数名称=参数值&参数名称=参数值
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(protocolConfig.getName()).append("://");
                // 此处可选择具体网卡设备
                String hostAddress = NetworkInterface.getNetworkInterfaces().
                        nextElement().getInterfaceAddresses().get(0).getAddress().getHostAddress();
                stringBuilder.append(hostAddress).append(":");
                stringBuilder.append(protocolConfig.getPort()).append("/");
                stringBuilder.append(serviceConfig.getService().getName()).append("?");
                // 版本号啥的的不写了......
                stringBuilder.append("transporter=").append(protocolConfig.getTransporter());
                stringBuilder.append("&serialization=").append(protocolConfig.getSerialization());

                URI exportUri = new URI(stringBuilder.toString());
                System.out.println("准备暴露服务：" + exportUri);

                // 2.2 创建服务 -- 多个 service 用同一个端口
                // TODO 思考点：一个系统，多个 service 需要暴露
                Protocol protocol = (Protocol) SpiUtils.getServiceImpl(protocolConfig.getName(), Protocol.class);
                protocol.export(exportUri, invoker);

                // 注册到中心
                for (RegistryConfig registryConfig : serviceConfig.getRegistryConfigs()) {
                    URI registryUri = new URI(registryConfig.getAddress());
                    RegistryService registryService =
                            (RegistryService) SpiUtils.getServiceImpl(registryUri.getScheme(), RegistryService.class);
                    registryService.init(registryUri);
                    registryService.register(exportUri);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端需要生成引用服务的代理对象
     *
     * @param referenceConfig 引用配置
     * @return Object
     */
    public static Object getReferenceBean(ReferenceConfig referenceConfig) {
        try {
            // 根据服务 通过注册中心，找到服务提供者实例
            ClusterInvoker clusterInvoker = new ClusterInvoker(referenceConfig);
            // 代理对象
            return ProxyFactory.getProxy(clusterInvoker, new Class[]{referenceConfig.getService()});
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}